<?php

namespace App\Http\Controllers\Api\Wechat;

use Illuminate\Support\Facades\Log;

class WxBase
{

	protected $AppId ;//APPID

	protected $AppSecret ;//APP秘钥

	protected $Mch_id ;	//商户号

	protected $Key ;//商户号密钥

	//统一下单请求的url
	protected $unifieorder_url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';

	//订单查询请求的url
	protected $queryOrder_url = 'https://api.mch.weixin.qq.com/pay/orderquery';

	//订单退款请求url
	protected $refund_url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';

	//初始化数据
	public function __construct($config){
		$this->AppId = $config['AppId'];
		$this->AppSecret = $config['AppSecret'];
		$this->Mch_id = $config['Mch_id'];
		$this->Key = $config['Key'];
	}

	//生成签名
	public function getSign($arr){
		//去除空值
		$arr = array_filter($arr);
		if(isset($arr['Sign'])){
			unset($arr['Sign']);
		}
		//按照键名字典排序
		ksort($arr);
		//生成url格式的字符串
		$str = $this->arrToUrl($arr) . '&key=' . $this->Key;

		return strtoupper(md5($str));
	}

	//获取带签名的数组
	public function setSign($arr){
		$arr['Sign'] = $this->getSign($arr);;
		return $arr;
	}

	//统一下单
	public function unifiedorder($out_trade_no, $money, $notify_url, $openid = '', $body = '购买商品', $type = '')
	{
		$params = [
			'appid'            => $this->AppId,
			'mch_id'           => $this->Mch_id,
			'nonce_str'        => md5(time()),
			'body'             => $body,
			'out_trade_no'     => $out_trade_no,
//			'total_fee'        => $money * 100,
            'total_fee'        => $money ,
			//$_SERVER['REMOTE_ADDR'],
			'spbill_create_ip' => $this->get_client_ip(),
			'notify_url'       => $notify_url,
			'trade_type'       => 'JSAPI',
			'product_id'       => $out_trade_no,
			// 'openid'    => $this->getOpenId()
		];
		if($type == 'h5'){
			$params['trade_type'] = 'MWEB';
		}else{
			$params['openid'] = $openid;
			if($openid == ''){
				$params['openid'] = $openid;
			}
		}

		//签名
		$params = $this->setSign($params);
		// Log::write('写入下单参数'.json_encode($params));

		$xmldata = $this->ArrToXml($params);
		$resdata = $this->postXml($this->unifieorder_url, $xmldata);
		// Log::write('写入返回参数'.$resdata);
		//将统一下单接口返回的结果转化成数组
		$arr = $this->XmlToArr($resdata);

		return $arr;
	}

	//获取openid
	public function getOpenId(){
		if(isset($_SESSION['openid'])){
			return $_SESSION['openid'];
		}else{
			//1.用户访问一个地址 先获取到code
			if(!isset($_GET['code'])){
				//print_r($_SERVER);
				$redurl = $_SERVER['REQUEST_SCHEME'] . 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
				$url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" .$this->AppId ."&redirect_uri={$redurl}&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
				//构建跳转地址 跳转
				header("location:{$url}");
			}else{
				//2.根据code获取到openid
				//调用接口获取openid
				$openidurl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" . $this->AppId . "&secret=".$this->AppSecret . "&code=" . $_GET['code'] . "&grant_type=authorization_code";
				$data = file_get_contents($openidurl);
				$arr = json_decode($data,true);
				$_SESSION['openid'] = $arr['openid'];
				return $_SESSION['openid'];
			}
		}
	}


	//调用查询订单接口
	public function queryOrder($oid){
		//构建数据
		$params = [
			'appid'        => $this->AppId,
			'mch_id'       => $this->Mch_id,
			'out_trade_no' => $oid,
			'nonce_str'    => md5(time()),
			'sign_type'    => 'MD5'
		];

		$params = $this->setSign($params);
		$xmldata = $this->ArrToXml($params);

		$resdata = $this->postXml($this->queryOrder_url, $xmldata);
		$arr = $this->XmlToArr($resdata);
		return $arr;
	}


	//获取终端ip
	public function get_client_ip()
	{
		if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
			$ip = getenv('HTTP_CLIENT_IP');
		} elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
			$ip = getenv('HTTP_X_FORWARDED_FOR');
		} elseif(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
			$ip = getenv('REMOTE_ADDR');
		} elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
			$ip = $_SERVER['REMOTE_ADDR'];
		}
		return preg_match ( '/[\d\.]{7,15}/', $ip, $matches ) ? $matches [0] : '';
	}

	//数组转xml
	public function ArrToXml($arr)
	{
		if(!is_array($arr) || count($arr) == 0) {
			return '';
		}

		$xml = "<xml>";
		foreach ($arr as $key=>$val) {
			if (is_numeric($val)){
				$xml.="<".$key.">".$val."</".$key.">";
			}else{
				$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
			}
		}
		$xml.="</xml>";
		return $xml;
	}

	public function XmlToArr($xml)
	{
		if($xml == '') {
			return '';
		}
		libxml_disable_entity_loader(true);
		$arr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
		return $arr;
	}


	public function postXml($url, $postfields)
	{
		$ch = curl_init();
		//请求url地址
		$params[CURLOPT_URL] = $url;
		//是否返回响应头信息
		$params[CURLOPT_HEADER] = false;
		//是否将结果返回
		$params[CURLOPT_RETURNTRANSFER] = true;
		//是否重定向
		$params[CURLOPT_FOLLOWLOCATION] = true;
		$params[CURLOPT_POST] = true;
		$params[CURLOPT_POSTFIELDS] = $postfields;
		$params[CURLOPT_SSL_VERIFYPEER] = false;
		$params[CURLOPT_SSL_VERIFYHOST] = false;
		//传入curl参数
		curl_setopt_array($ch, $params);
		//执行
		$content = curl_exec($ch);
		//关闭连接
		curl_close($ch);
		return $content;
	}

	public function arrToUrl($arr)
	{
		return urldecode(http_build_query($arr));
	}


	//获取公众号支付所需要的json数据
	public function getJsParams($prepay_id)
	{
		$params = [
			'appId'     => $this->AppId,
			'timeStamp' => strval(time()),
			'nonceStr'  => md5(time()),
			'package'   => 'prepay_id=' . $prepay_id,
			'signType'  => 'MD5',
			//       'paySign' => $this->getSign($params)
		];
		$params['paySign'] = $this->getSign($params);
		return $params;
	}

	public function postXmlCurl($url, $vars, $type, $second = 30, $aHeader = array())
	{
		if ($type == 1) {
			$isdir = getcwd().'/extend/Wechat/cert/withdrawl/';//证书位置
		} else {
			$isdir = getcwd().'/extend/Wechat/cert/refund/';//证书位置
		}

		$ch = curl_init();//初始化curl

		curl_setopt($ch, CURLOPT_TIMEOUT, $second);//设置执行最长秒数
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//要求结果为字符串且输出到屏幕上
		curl_setopt($ch, CURLOPT_URL, $url);//抓取指定网页
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);// 终止从服务端进行验证
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);//
		curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');//证书类型
		curl_setopt($ch, CURLOPT_SSLCERT, $isdir . 'apiclient_cert.pem');//证书位置
		curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');//CURLOPT_SSLKEY中规定的私钥的加密类型
		curl_setopt($ch, CURLOPT_SSLKEY, $isdir . 'apiclient_key.pem');//证书位置
		curl_setopt($ch, CURLOPT_CAINFO, 'PEM');
		curl_setopt($ch, CURLOPT_CAINFO, $isdir . 'rootca.pem');
		if (count($aHeader) >= 1) {
			curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);//设置头部
		}
		curl_setopt($ch, CURLOPT_POST, 1);//post提交方式
		curl_setopt($ch, CURLOPT_POSTFIELDS, $vars);//全部数据使用HTTP协议中的"POST"操作来发送

		$data = curl_exec($ch);//执行回话
		$error = curl_errno($ch);
		if ($data) {
			curl_close($ch);
			return $data;
		} else {
			echo "call faild, errorCode:$error\n";
			curl_close($ch);
			return false;
		}
	}

	public function dotransfer($transfer,&$msg=''){

		$url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";

		$parameters = array(
			'mch_appid' => $this->AppId,//绑定支付的APPID
			'mchid' => $this->Mch_id,//商户号
			'nonce_str' => md5(time()), //生成32位的随机字符串，见图1
			'partner_trade_no' => $transfer['payment_id'],  //商户订单号，不能重复使用
			'openid' => $transfer['open_id'],//用户的open_id
			'check_name' => 'NO_CHECK',//是否检查姓名
			//'re_user_name' => $transfer['real_name'],  //真实姓名
			'amount' => bcmul($transfer['amount'],100,0),   //企业付款金额，单位为分  最低1元
			'desc' => '佣金提现',//备注
			'spbill_create_ip' => strval($_SERVER['SERVER_ADDR']),//服务器IP
		);
		$parameters['Sign'] = $this->getSign($parameters, $this->Key);//getSign函数见图2,C('KEY'):商户支付密钥
		$xml = $this->ArrToXml($parameters);//函数见图3
		$response = $this->postXmlCurl($url , $xml, 1);//函数见图4

		$result = $this->XmlToArr($response);//函数见图片5

		if($result['return_code']=='SUCCESS'){
			if($result['result_code']=='SUCCESS'){
				$result['status'] = 1;
				return $result;
			}else{
				$result['status'] = 0;
				return $result;
			}
		}else{
			//echo '付款成功,微信接口异常';
			$result['status'] = 0;
		}
	}

	//微信退款
	public function refund($out_trade_no, $money, $out_refund_no, $refund_fee, $notify_url)
	{
		$params = [
			'appid'            => $this->AppId,
			'mch_id'           => $this->Mch_id,
			'nonce_str'        => md5(time()),
			'out_trade_no'     => $out_trade_no,
			'out_refund_no'    => $out_refund_no,
			'total_fee'        => $money * 100,
			'refund_fee'	   => $refund_fee,
		];

		//签名
		$params = $this->setSign($params);
		$xmldata = $this->ArrToXml($params);
		$resdata = $this->postXmlCurl($this->refund_url, $xmldata, 2);
		$result = $this->XmlToArr($resdata);

		if($result['return_code']=='SUCCESS'){
			if($result['result_code']=='SUCCESS'){
				$result['status'] = 1;
				return $result;
			}else{
				$result['status'] = 0;
				return $result;
			}
		}else{
			//echo '付款成功,微信接口异常';
			$result['status'] = 0;
		}
	}
}
